﻿using System.Collections.Generic;
using System.Linq;
using DependencyAnalysis.DataModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using theeg.DependencyAnalysis.CommonAddin.Models;
using theeg.GraphWpf.Models;

namespace UnitTests.Addin
{
    [TestClass]
    public class ProximityModelTest
    {
        private IDependencyModel _dependencyModel;
        private ProximityModel _proximityModel;
        private AddinModel _addinModel;

        [TestInitialize]
        public void Initialize()
        {
            _addinModel = new AddinModel(new SolutionStub());
            _dependencyModel = new DependencyModel();
            _addinModel.DependencyModel = _dependencyModel;
            var descriptor = DependencyModelTest.BuildDependencyDescriptor(1, 2, true, false);
            _dependencyModel.Add(descriptor);
            descriptor = DependencyModelTest.BuildDependencyDescriptor(1, 3, true, false);
            _dependencyModel.Add(descriptor);
            descriptor = DependencyModelTest.BuildDependencyDescriptor(2, 3, true, false);
            _dependencyModel.Add(descriptor);

            _proximityModel = _addinModel.ProximityModel;
        }

        [TestMethod]
        public void WhenDescriptorIsNullThenSetGraphContentToNull()
        {
            _proximityModel.GraphContent = new GraphParameter();
            _proximityModel.ChangeDescriptor(new GraphParameter());
            Assert.IsNull(_proximityModel.GraphContent);
        }

        [TestMethod]
        public void WhenDescriptorIsNullThenSetDependenciesToNull()
        {
            _proximityModel.GraphContent = new GraphParameter();
            _proximityModel.ChangeDescriptor(new GraphParameter());
            Assert.IsNull(_addinModel.Dependencies);
        }

        [TestMethod]
        public void WhenDescriptorIsChangedThenSetDependenciesToNull()
        {
            _addinModel.Dependencies = new DependencyDescriptor[0];
            var parameter = new GraphParameter { Descriptor = new ModuleDescriptor { Identifier = "Module1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.IsNull(_addinModel.Dependencies);
        }

        [TestMethod]
        public void WhenDescriptorIsModuleThenSetGraphContentToDescriptor()
        {
            _addinModel.Dependencies = new DependencyDescriptor[0];
            var parameter = new GraphParameter { Descriptor = new ModuleDescriptor { Identifier = "Module1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(parameter, _proximityModel.GraphContent);
        }

        [TestMethod]
        public void WhenDescriptorIsSubmoduleThenSetGraphContentToDescriptor()
        {
            var parameter = new GraphParameter { Descriptor = new SubmoduleDescriptor { Identifier = "Module1.Submodule1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(parameter, _proximityModel.GraphContent);
        }

        [TestMethod]
        public void WhenDescriptorIsTypeThenSetGraphContentToDescriptor()
        {
            var parameter = new GraphParameter { Descriptor = new TypeDescriptor { Identifier = "Module1.Submodule1.Type1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(parameter, _proximityModel.GraphContent);
        }

        [TestMethod]
        public void WhenDescriptorIsMemberThenSetGraphContentToDescriptor()
        {
            var parameter = new GraphParameter { Descriptor = new MemberDescriptor { Identifier = "Module1.Submodule1.Type1.Member1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(parameter, _proximityModel.GraphContent);
        }

        [TestMethod]
        public void WhenDescriptorIsNotFoundThenThrowException()
        {
            var parameter = new GraphParameter { Descriptor = new MemberDescriptor { Identifier = "Dummy" } };
            Assert1.Throws<KeyNotFoundException>(() => _proximityModel.ChangeDescriptor(parameter));
        }

        [TestMethod]
        public void WhenDescriptorIsTransitionThenDoNotChangeGraphContent()
        {
            var original = new GraphParameter();
            _proximityModel.GraphContent = original;

            var parameter = new GraphParameter { Descriptor = new TransitionDescriptor { Identifier = "Module1.Submodule1.Type1.Member1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(original, _proximityModel.GraphContent);
        }

        [TestMethod]
        public void WhenDescriptorHasChangedThenCreateGraphNodes()
        {
            _addinModel.Dependencies = new DependencyDescriptor[0];
            var parameter = new GraphParameter { Descriptor = new ModuleDescriptor { Identifier = "Module1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(3, _proximityModel.GraphContent.Nodes.Count);
        }

        [TestMethod]
        public void WhenDescriptorHasChangedThenCreateGraphTransitions()
        {
            _addinModel.Dependencies = new DependencyDescriptor[0];
            var parameter = new GraphParameter { Descriptor = new ModuleDescriptor { Identifier = "Module1" } };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(2, _proximityModel.GraphContent.Transitions.Count);
        }

        [TestMethod]
        public void WhenQueryingTransitionBetweenMembersThenSetDependencies()
        {
            var parameter = new GraphParameter
                {
                    Descriptor = new TransitionDescriptor
                        {
                            Source = new MemberDescriptor { Identifier = "Module1.Submodule1.Type1.Member1" },
                            Target = new MemberDescriptor { Identifier = "Module2.Submodule2.Type2.Member2" }
                        }
                };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(1, _addinModel.Dependencies.Count());
        }

        [TestMethod]
        public void WhenQueryingTransitionBetweenTypesThenSetDependencies()
        {
            var parameter = new GraphParameter
            {
                Descriptor = new TransitionDescriptor
                {
                    Source = new TypeDescriptor { Identifier = "Module1.Submodule1.Type1" },
                    Target = new TypeDescriptor { Identifier = "Module2.Submodule2.Type2" }
                }
            };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(1, _addinModel.Dependencies.Count());
        }

        [TestMethod]
        public void WhenQueryingTransitionBetweenSubmodulesThenSetDependencies()
        {
            var parameter = new GraphParameter
            {
                Descriptor = new TransitionDescriptor
                {
                    Source = new SubmoduleDescriptor { Identifier = "Module1.Submodule1" },
                    Target = new SubmoduleDescriptor { Identifier = "Module2.Submodule2" }
                }
            };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(1, _addinModel.Dependencies.Count());
        }

        [TestMethod]
        public void WhenQueryingTransitionBetweenModulesThenSetDependencies()
        {
            var parameter = new GraphParameter
            {
                Descriptor = new TransitionDescriptor
                {
                    Source = new ModuleDescriptor { Identifier = "Module1" },
                    Target = new ModuleDescriptor { Identifier = "Module2" }
                }
            };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(1, _addinModel.Dependencies.Count());
        }

        [TestMethod]
        public void WhenTransitionSourceNotFoundThenDependenciesAreZero()
        {
            var parameter = new GraphParameter
            {
                Descriptor = new TransitionDescriptor
                {
                    Source = new ModuleDescriptor { Identifier = "Dummy" },
                    Target = new ModuleDescriptor { Identifier = "Module2" }
                }
            };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(0, _addinModel.Dependencies.Count());
        }

        [TestMethod]
        public void WhenTransitionTargetNotFoundThenDependenciesAreZero()
        {
            var parameter = new GraphParameter
            {
                Descriptor = new TransitionDescriptor
                {
                    Source = new ModuleDescriptor { Identifier = "Module1" },
                    Target = new ModuleDescriptor { Identifier = "Dummy" }
                }
            };
            _proximityModel.ChangeDescriptor(parameter);

            Assert.AreEqual(0, _addinModel.Dependencies.Count());
        }

        [TestMethod]
        public void BuildNodeSetDescriptorAsDataObject()
        {
            var descriptor = new MemberDescriptor { FullName = "Hello" };
            var node = GraphBuilder.BuildNode<SubGraph>(descriptor);

            Assert.AreEqual(descriptor, node.DataObject);
        }
    }
}
